1 /****************************** Module Header ******************************\
2 * Module Name: FileDragAndDropExt.cpp
3 * Project: ATLShellExtDragAndDropHandler
4 * Copyright (c) Microsoft Corporation.
6 * FileDragAndDropExt is an example of drag-and-drop handler for file objects.
7 * After the setup of the handler, when you right-click any files to drag the
8 * files to a directory or the desktop, a context menu with "All-In-One Code
9 * Framework" menu item will be displayed. Clicking the menu item prompts a
10 * message box that shows the files being dragged and the target location that
11 * the files are dropped to.
13 * This source is subject to the Microsoft Public License.
14 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
15 * All other rights reserved.
17 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
18 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
20 \***************************************************************************/
22 #pragma region Includes
24 #include "FileDragAndDropExt.h"
28 /////////////////////////////////////////////////////////////////////////////
29 // CFileDragAndDropExt IShellExtInit methods.
33 // FUNCTION: CFileDragAndDropExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT,
36 // PURPOSE: Initializes a property sheet extension, shortcut menu extension,
37 // or drag-and-drop handler.
39 IFACEMETHODIMP
CFileDragAndDropExt::Initialize(
40 LPCITEMIDLIST pidlFolder
, LPDATAOBJECT pDataObj
, HKEY hProgID
)
42 // Get the name of the directory where the files were dropped
43 if (!SHGetPathFromIDList(pidlFolder
, m_szFolderDroppedIn
))
46 // Get a list of all the objects that were dropped
53 FORMATETC fe
= { CF_HDROP
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
56 // pDataObj contains the objects being acted upon. In this example,
57 // we get an HDROP handle for enumerating the selected files.
58 if (FAILED(pDataObj
->GetData(&fe
, &stm
)))
61 // Get an HDROP handle.
62 HDROP hDrop
= (HDROP
)GlobalLock(stm
.hGlobal
);
65 ReleaseStgMedium(&stm
);
69 // Determine how many files are involved in this operation
70 UINT nFiles
= DragQueryFile(hDrop
, 0xFFFFFFFF, NULL
, 0);
73 GlobalUnlock(stm
.hGlobal
);
74 ReleaseStgMedium(&stm
);
78 // Enumerates through the selected files and directories
79 TCHAR szFileName
[MAX_PATH
];
80 for (UINT i
= 0; i
< nFiles
; i
++)
82 // Get the next filename
83 if (0 == DragQueryFile(hDrop
, i
, szFileName
, MAX_PATH
))
86 m_lsFiles
.push_back(szFileName
);
90 GlobalUnlock(stm
.hGlobal
);
91 ReleaseStgMedium(&stm
);
93 // If we found any files we can work with, return S_OK. Otherwise return
94 // E_INVALIDARG so we don't get called again for this drag-and-drop
96 return (m_lsFiles
.size() > 0) ? S_OK
: E_INVALIDARG
;
100 /////////////////////////////////////////////////////////////////////////////
101 // CFileDragAndDropExt IContextMenu methods.
104 #define IDM_SAMPLE 0 // The command's identifier offset.
108 // FUNCTION: CFileContextMenuExt::OnSample(HWND)
110 // PURPOSE: OnSample handles the "Sample" verb of the shell extension.
112 void CFileDragAndDropExt::OnSample(HWND hWnd
)
114 // Concat the dragged files to a string
115 DWORD dwBufferSize
= m_lsFiles
.size() * MAX_PATH
;
116 TCHAR
* pszFiles
= new TCHAR
[dwBufferSize
];
117 ZeroMemory(pszFiles
, dwBufferSize
);
119 string_list::const_iterator end
;
120 for (string_list::const_iterator it
= m_lsFiles
.begin(),
121 end
= m_lsFiles
.end();
124 _tcscat_s(pszFiles
, dwBufferSize
, it
->c_str());
125 _tcscat_s(pszFiles
, dwBufferSize
, _T("\n"));
128 TCHAR
* pszMessage
= new TCHAR
[512 + dwBufferSize
];
129 _stprintf_s(pszMessage
, 512 + dwBufferSize
, _T("Drag-and-drop handler") \
130 _T("\n\nSource file(s):\n%s\nTarge location:\n%s"), pszFiles
,
131 m_szFolderDroppedIn
);
133 MessageBox(hWnd
, pszMessage
, _T("ATLShellExtDragAndDropHandler"),
142 // FUNCTION: CFileDragAndDropExt::QueryContextMenu(HMENU, UINT, UINT, UINT,
145 // PURPOSE: The Shell calls IContextMenu::QueryContextMenu to allow the
146 // context menu handler to add its menu items to the menu. It
147 // passes in the HMENU handle in the hmenu parameter. The
148 // indexMenu parameter is set to the index to be used for the
149 // first menu item that is to be added.
151 IFACEMETHODIMP
CFileDragAndDropExt::QueryContextMenu(
152 HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
154 // If uFlags include CMF_DEFAULTONLY then we should not do anything
155 if (CMF_DEFAULTONLY
& uFlags
)
157 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, USHORT(0));
160 // Use either InsertMenu or InsertMenuItem to add menu items to the list
161 InsertMenu(hMenu
, indexMenu
, MF_STRING
| MF_BYPOSITION
, idCmdFirst
+
162 IDM_SAMPLE
, _T("&All-In-One Code Framework"));
164 // Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
165 // Set the code value to the offset of the largest command identifier
166 // that was assigned, plus one (1)
167 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, USHORT(IDM_SAMPLE
+ 1));
172 // FUNCTION: CFileDragAndDropExt::InvokeCommand(LPCMINVOKECOMMANDINFO)
174 // PURPOSE: This method is called when a user clicks a menu item to tell
175 // the handler to run the associated command. The lpcmi parameter
176 // points to a structure that contains the needed information.
178 IFACEMETHODIMP
CFileDragAndDropExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
180 // The high-word of lpcmi->lpVerb must be NULL because we did not
181 // implement IContextMenu::GetCommandString to specify any verb for the
183 if (NULL
!= HIWORD(lpcmi
->lpVerb
))
188 // Then, the low-word of lpcmi->lpVerb should contain the command's
190 if (LOWORD(lpcmi
->lpVerb
) == IDM_SAMPLE
)
192 OnSample(lpcmi
->hwnd
);
196 // If the verb is not recognized by the drag-and-drop handler, it
197 // must return E_FAIL to allow it to be passed on to the other
198 // drag-and-drop handlers that might implement that verb.